<script lang="tsx">
import type { InfiniteData, UseInfiniteQueryReturnType } from '@peng_kai/kit/libs/vue-query';
import type { UnwrapRef } from 'vue';
import { Empty, Error, Loading } from '../suspense';
import IntersectChecker from './IntersectChecker.vue';
import LoadMore from './LoadMore.vue';
</script>

<script setup lang="tsx" generic="T extends UseInfiniteQueryReturnType<any, any>">
type TRes = NonNullable<UnwrapRef<T['data']>>;
type TData = TRes extends InfiniteData<infer D, any> ? D : unknown;
type TList = NonNullable<TData> extends { list: infer L } ? NonNullable<L> extends Array<any> ? NonNullable<L> : any : any;

defineOptions({
  inheritAttrs: false,
});
const props = defineProps<{
  querier: T;
  forKey?: string;
  scrollLoad?: boolean;
  loadingOutRender?: boolean | 'initLoading' | 'moreLoading';
}>();

const querier = props.querier;
const list = computed(() => querier.data.value?.pages.map((page: any) => page?.list ?? []).flat());
const pagination = computed(() => querier.data.value?.pages.at(-1)?.pagination);
const currentPageNum = computed(() => querier.data.value?.pages?.length ?? 0);
const queryState = reactive({
  isInitLoading: computed(() =>
    (querier.isLoading.value && currentPageNum.value === 0)
    || querier.isRefetching.value,
  ),
  isInitError: computed(() =>
    querier.isError.value
    && !querier.isFetching.value
    && currentPageNum.value === 0,
  ),
  isEmpty: computed(() =>
    querier.isSuccess.value
    && !querier.data.value?.pages?.[0]?.list?.length,
  ),
  isMoreLoading: computed(() =>
    querier.isFetching.value && !querier.isRefetching.value
    && currentPageNum.value > 0,
  ),
  isMoreError: computed(() =>
    querier.isError.value
    && !querier.isFetching.value
    && currentPageNum.value > 0,
  ),
  isNoMore: computed(() =>
    !querier.isFetching.value
    && !querier.hasNextPage.value
    && currentPageNum.value > 0
    && !!querier.data.value?.pages?.[0]?.list?.length,
  ),
});

function fetchNextPage() {
  if (querier.fetchStatus.value !== 'fetching')
    return querier.fetchNextPage();
}
</script>

<template>
  <template v-if="!queryState.isInitLoading">
    <template v-for="(item, i) of (list as TList)" :key="forKey ? item[forKey] : i">
      <slot name="default" :item="item" />
    </template>
  </template>

  <!-- 外部 Loading -->
  <slot v-if="props.loadingOutRender && (queryState.isInitLoading || queryState.isMoreLoading)" name="loading">
    <slot v-if="props.loadingOutRender === 'initLoading' && queryState.isInitLoading" name="initLoading">
      <Loading />
    </slot>
    <slot v-if="props.loadingOutRender === 'moreLoading' && queryState.isMoreLoading" name="moreLoading">
      <Loading />
    </slot>
  </slot>

  <div v-bind="$attrs">
    <!-- 内部 Loading -->
    <slot v-if="!props.loadingOutRender && (queryState.isInitLoading || queryState.isMoreLoading)" name="loading">
      <slot v-if="queryState.isInitLoading" name="initLoading">
        <Loading />
      </slot>
      <slot v-if="queryState.isMoreLoading" name="moreLoading">
        <Loading />
      </slot>
    </slot>

    <slot v-if="queryState.isInitError || queryState.isMoreError" name="error">
      <slot v-if="queryState.isInitError" name="initError">
        <Error />
      </slot>
      <slot v-if="queryState.isMoreError" name="moreError">
        <Error />
      </slot>
    </slot>

    <slot v-if="queryState.isEmpty" name="empty">
      <Empty />
    </slot>

    <slot v-if="queryState.isNoMore" name="noMore">
      <div class="h-13 flex items-center justify-center text-sm text-sys-text-body">
        {{ $t('bf9dFxYzpXdbK3exrwxT') }}
      </div>
    </slot>

    <IntersectChecker v-if="props.scrollLoad" @intersect="fetchNextPage" />
    <LoadMore
      v-if="!props.scrollLoad && !queryState.isNoMore && !queryState.isEmpty"
      :loading="queryState.isInitLoading || queryState.isMoreLoading"
      :current="pagination && (pagination.page * pagination.page_size)"
      :total="pagination?.total"
      @load="fetchNextPage"
    />
  </div>
</template>
